const cap = require('cap');
const readline = require('readline');
const winston = require("winston");
const net = require('net');
const zlib = require('zlib');
const express = require('express');
const pb = require('./algo/pb');
const SRPacketProcessor = require('./StarResonanceDamageCounter/algo/packet');
const Readable = require("stream").Readable;
const fs = require('fs');
const path = require('path');
const Cap = cap.Cap;
const decoders = cap.decoders;
const PROTOCOL = decoders.PROTOCOL;
const print = console.log;
const app = express();

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
const devices = cap.deviceList();

function ask(question) {
    return new Promise(resolve => {
        rl.question(question, answer => {
            resolve(answer);
        });
    });
}

class Lock {
    constructor() {
        this.queue = [];
        this.locked = false;
    }

    async acquire() {
        if (this.locked) {
            return new Promise((resolve) => this.queue.push(resolve));
        }
        this.locked = true;
    }

    release() {
        if (this.queue.length > 0) {
            const nextResolve = this.queue.shift();
            nextResolve();
        } else {
            this.locked = false;
        }
    }
}

// ========= 采用与新版源码一致的数据模型 =========
class StatisticData {
    constructor() {
        this.stats = { normal: 0, critical: 0, lucky: 0, crit_lucky: 0, hpLessen: 0, total: 0 };
        this.count = { normal: 0, critical: 0, lucky: 0, total: 0 };
        this.realtimeWindow = [];
        this.timeRange = [];
        this.realtimeStats = { value: 0, max: 0 };
    }
    addRecord(value, isCrit, isLucky, hpLessenValue = 0) {
        const now = Date.now();
        if (isCrit) {
            if (isLucky) this.stats.crit_lucky += value; else this.stats.critical += value;
        } else if (isLucky) {
            this.stats.lucky += value;
        } else {
            this.stats.normal += value;
        }
        this.stats.total += value;
        this.stats.hpLessen += hpLessenValue;
        if (isCrit) this.count.critical++;
        if (isLucky) this.count.lucky++;
        if (!isCrit && !isLucky) this.count.normal++;
        this.count.total++;
        this.realtimeWindow.push({ time: now, value });
        if (this.timeRange[0]) this.timeRange[1] = now; else this.timeRange[0] = now;
    }
    updateRealtimeStats() {
        const now = Date.now();
        while (this.realtimeWindow.length > 0 && now - this.realtimeWindow[0].time > 1000) this.realtimeWindow.shift();
        this.realtimeStats.value = this.realtimeWindow.reduce((s, e) => s + e.value, 0);
        if (this.realtimeStats.value > this.realtimeStats.max) this.realtimeStats.max = this.realtimeStats.value;
    }
    getTotalPerSecond() {
        if (!this.timeRange[0] || !this.timeRange[1]) return 0;
        const v = (this.stats.total / (this.timeRange[1] - this.timeRange[0]) * 1000) || 0;
        return Number.isFinite(v) ? v : 0;
    }
    reset() {
        this.stats = { normal: 0, critical: 0, lucky: 0, crit_lucky: 0, hpLessen: 0, total: 0 };
        this.count = { normal: 0, critical: 0, lucky: 0, total: 0 };
        this.realtimeWindow = [];
        this.timeRange = [];
        this.realtimeStats = { value: 0, max: 0 };
    }
}

class UserData {
    constructor(uid) {
        this.uid = uid;
        this.name = '';
        this.damageStats = new StatisticData();
        this.healingStats = new StatisticData();
        this.takenDamage = 0;
        this.profession = '未知';
        this.skillUsage = new Map();
        this.fightPoint = 0;
    }
    addDamage(skillId, damage, isCrit, isLucky, hpLessenValue = 0) {
        this.damageStats.addRecord(damage, isCrit, isLucky, hpLessenValue);
        if (!this.skillUsage.has(skillId)) this.skillUsage.set(skillId, new StatisticData());
        this.skillUsage.get(skillId).addRecord(damage, isCrit, isLucky, hpLessenValue);
        this.skillUsage.get(skillId).realtimeWindow.length = 0;
    }
    addHealing(healing, isCrit, isLucky) { this.healingStats.addRecord(healing, isCrit, isLucky); }
    addTakenDamage(damage) { this.takenDamage += damage; }
    setProfession(p) { this.profession = p; }
    updateRealtimeDps() { this.damageStats.updateRealtimeStats(); this.healingStats.updateRealtimeStats(); }
    getTotalDps() { return this.damageStats.getTotalPerSecond(); }
    getTotalHps() { return this.healingStats.getTotalPerSecond(); }
    getTotalCount() {
        return {
            normal: this.damageStats.count.normal + this.healingStats.count.normal,
            critical: this.damageStats.count.critical + this.healingStats.count.critical,
            lucky: this.damageStats.count.lucky + this.healingStats.count.lucky,
            total: this.damageStats.count.total + this.healingStats.count.total,
        };
    }
    getSummary() {
        return {
            realtime_dps: this.damageStats.realtimeStats.value,
            realtime_dps_max: this.damageStats.realtimeStats.max,
            total_dps: this.getTotalDps(),
            total_damage: { ...this.damageStats.stats },
            total_count: this.getTotalCount(),
            realtime_hps: this.healingStats.realtimeStats.value,
            realtime_hps_max: this.healingStats.realtimeStats.max,
            total_hps: this.getTotalHps(),
            total_healing: { ...this.healingStats.stats },
            taken_damage: this.takenDamage,
            profession: this.profession,
            name: this.name,
            fightPoint: this.fightPoint,
        };
    }
    setName(n) { this.name = n; }
    setFightPoint(fp) { this.fightPoint = fp; }
    reset() { this.damageStats.reset(); this.healingStats.reset(); this.takenDamage = 0; this.profession = '未知'; this.skillUsage.clear(); this.fightPoint = 0; }
}

// 按技能ID推断职业
const skillIdToProfession = { 1241: '射线', 55302: '协奏', 20301: '愈合', 1518: '惩戒', 2306: '狂音', 120902: '冰矛', 1714: '居合', 44701: '月刃', 2203622: '鹰弓',1700827:'狼弓',1419:'空枪',1418:'重装',2405:'防盾',2406:'光盾',199902:'岩盾' };

class UserDataManager {
    constructor() { this.users = new Map(); }
    getUser(uid) { if (!this.users.has(uid)) this.users.set(uid, new UserData(uid)); return this.users.get(uid); }
    addDamage(uid, skillId, damage, isCrit, isLucky, hpLessenValue = 0) {
        const u = this.getUser(uid); u.addDamage(skillId, damage, isCrit, isLucky, hpLessenValue);
        // 如未识别职业，使用技能ID推断
        if ((!u.profession || u.profession === '未知') && skillIdToProfession[skillId]) u.setProfession(skillIdToProfession[skillId]);
    }
    addHealing(uid, healing, isCrit, isLucky) { this.getUser(uid).addHealing(healing, isCrit, isLucky); }
    addTakenDamage(uid, damage) { this.getUser(uid).addTakenDamage(damage); }
    setProfession(uid, p) { this.getUser(uid).setProfession(p); }
    setName(uid, n) { this.getUser(uid).setName(n); }
    setFightPoint(uid, fp) { this.getUser(uid).setFightPoint(fp); }
    updateAllRealtimeDps() { for (const u of this.users.values()) u.updateRealtimeDps(); }
    getAllUsersData() { const r = {}; for (const [uid, u] of this.users.entries()) r[uid] = u.getSummary(); return r; }
    clearAll() { this.users.clear(); }
}

const userDataManager = new UserDataManager();

// 技能ID到技能名称的映射 (从文件加载)
let skillNameMap = {};
// 用户ID到昵称的映射 (从文件加载)
let nicknameMap = {};

// 职业ID到职业名称的映射
const professionMap = {
    1: '战士',
    2: '法师', 
    3: '射手',
    4: '刺客',
    5: '坦克',
    6: '辅助',
    7: '治疗',
    8: '雷影剑士',
    9: '居合流',
    10: '雷影剑士-居合流',
    11: '神秘职业11',
    13: '神秘职业13',
    14: '神秘职业14',
    15: '神秘职业15',
    18: '神秘职业18',
    19: '神秘职业19',
    20: '神秘职业20',
    21: '神秘职业21',
    26: '神秘职业26',
    29: '神秘职业29',
    40: '神秘职业40',
    // 基于观察到的日志数据添加的职业ID
};

// 加载技能名称配置文件
function loadSkillNames() {
    try {
        const skillConfigPath = path.join(__dirname, 'skill_names.json');
        if (fs.existsSync(skillConfigPath)) {
            const configData = fs.readFileSync(skillConfigPath, 'utf8');
            const config = JSON.parse(configData);
            skillNameMap = config.skill_names || {};
            console.log(`已加载 ${Object.keys(skillNameMap).length} 个技能名称配置`);
        } else {
            // 如果文件不存在，创建默认配置
            const defaultConfig = {
                skill_names: {
                    1001: '普通攻击',
                    1002: '技能释放',
                    1003: '终极技能',
                    2001: '治疗技能',
                    2002: '辅助技能'
                },
                last_updated: new Date().toISOString()
            };
            fs.writeFileSync(skillConfigPath, JSON.stringify(defaultConfig, null, 4), 'utf8');
            skillNameMap = defaultConfig.skill_names;
            console.log('已创建默认技能名称配置文件');
        }
    } catch (error) {
        console.error('加载技能名称配置失败:', error);
        // 使用默认配置
        skillNameMap = {
            1001: '普通攻击',
            1002: '技能释放',
            1003: '终极技能',
            2001: '治疗技能',
            2002: '辅助技能'
        };
    }
}

// 保存技能名称配置到文件
function saveSkillNames() {
    try {
        const skillConfigPath = path.join(__dirname, 'skill_names.json');
        const config = {
            skill_names: skillNameMap,
            last_updated: new Date().toISOString()
        };
        fs.writeFileSync(skillConfigPath, JSON.stringify(config, null, 4), 'utf8');
        console.log('技能名称配置已保存到文件');
    } catch (error) {
        console.error('保存技能名称配置失败:', error);
    }
}

// 加载昵称配置文件
function loadNicknames() {
    try {
        const nicknameConfigPath = path.join(__dirname, 'nicknames.json');
        if (fs.existsSync(nicknameConfigPath)) {
            const configData = fs.readFileSync(nicknameConfigPath, 'utf8');
            const config = JSON.parse(configData);
            nicknameMap = config.nicknames || {};
            console.log(`已加载 ${Object.keys(nicknameMap).length} 个昵称配置`);
        } else {
            // 如果文件不存在，创建默认配置
            const defaultConfig = {
                nicknames: {},
                last_updated: new Date().toISOString()
            };
            fs.writeFileSync(nicknameConfigPath, JSON.stringify(defaultConfig, null, 4), 'utf8');
            nicknameMap = defaultConfig.nicknames;
            console.log('已创建默认昵称配置文件');
        }
    } catch (error) {
        console.error('加载昵称配置失败:', error);
        nicknameMap = {};
    }
}

// 保存昵称配置到文件
function saveNicknames() {
    try {
        const nicknameConfigPath = path.join(__dirname, 'nicknames.json');
        const config = {
            nicknames: nicknameMap,
            last_updated: new Date().toISOString()
        };
        fs.writeFileSync(nicknameConfigPath, JSON.stringify(config, null, 4), 'utf8');
        console.log('昵称配置已保存到文件');
    } catch (error) {
        console.error('保存昵称配置失败:', error);
    }
}

// 根据技能ID和上下文获取技能名称
function getSkillDisplayName(skillId, damage, isCrit, luckyValue, hpLessen) {
    // 首先检查预定义的技能映射
    if (skillNameMap[skillId]) {
        return skillNameMap[skillId];
    }
    
    // 根据伤害类型和数值推断技能类型
    let skillType = '';
    if (hpLessen > 0) {
        skillType = damage > 0 ? '复合技能' : '治疗技能';
    } else if (damage > 0) {
        if (damage > 10000) {
            skillType = '高伤技能';
        } else if (damage > 5000) {
            skillType = '中伤技能';
        } else {
            skillType = '低伤技能';
        }
    } else {
        skillType = '辅助技能';
    }
    
    return `${skillType}_${skillId}`;
}

async function main() {
    print('Welcome to use Damage Counter for Star Resonance by Dimole!');
    print('Version: V2.1');
    
    // 加载技能名称配置
    loadSkillNames();
    // 加载昵称配置
    loadNicknames();
    for (let i = 0; i < devices.length; i++) {
        print(i + '.\t' + devices[i].description);
    }
    const num = await ask('Please enter the number of the device used for packet capture: ');
    if (!devices[num]) {
        print('Cannot find device ' + num + '!');
        process.exit(1);
    }
    const log_level = await ask('Please enter log level (info|debug): ') || 'info';
    if (!log_level || !['info', 'debug'].includes(log_level)) {
        print('Invalid log level!');
        process.exit(1);
    }
    rl.close();
    const logger = winston.createLogger({
        level: log_level,
        format: winston.format.combine(
            winston.format.colorize({ all: true }),
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
            winston.format.printf(info => {
                return `[${info.timestamp}] [${info.level}] ${info.message}`;
            })
        ),
        transports: [
            new winston.transports.Console()
        ]
    });

    // 使用源码的数据包处理器，确保治疗/承伤/伤害解析的稳定性
    const packetProcessor = new SRPacketProcessor({ logger, userDataManager });

    // 瞬时DPS/HPS 更新
    setInterval(() => { userDataManager.updateAllRealtimeDps(); }, 100);

    //express
    app.use(express.static('public'));
    app.get('/api/data', (req, res) => {
        const user = userDataManager.getAllUsersData();
        // 兼容：透传 nickname/name
        Object.keys(user).forEach(uid => {
            if (!user[uid].nickname && nicknameMap[uid]) user[uid].nickname = nicknameMap[uid];
        });
        res.json({ code: 0, user });
    });
    app.get('/api/clear', (req, res) => {
        userDataManager.clearAll();
        logger.info('Statistics have been cleared!');
        res.json({
            code: 0,
            msg: 'Statistics have been cleared!',
        });
    });

    app.post('/api/update-skill-name', express.json(), (req, res) => {
        const { skillId, skillName } = req.body;
        if (!skillId || !skillName) {
            res.json({
                code: 1,
                msg: 'Missing skillId or skillName'
            });
            return;
        }
        
        // 更新技能名称映射
        skillNameMap[skillId] = skillName;
        
        // 保存到文件
        saveSkillNames();
        
        logger.info(`Updated skill name: ${skillId} -> ${skillName}`);
        
        res.json({
            code: 0,
            msg: 'Skill name updated successfully and saved to file'
        });
    });

    app.get('/api/skill-names', (req, res) => {
        res.json({
            code: 0,
            data: skillNameMap
        });
    });

    app.post('/api/update-nickname', express.json(), (req, res) => {
        const { uid, nickname } = req.body;
        if (!uid) {
            res.json({ code: 1, msg: '用户ID不能为空' });
            return;
        }
        // 空字符串表示删除
        if (nickname === '') {
            delete nicknameMap[uid];
        } else if (typeof nickname === 'string') {
        nicknameMap[uid] = nickname;
        } else {
            res.json({ code: 1, msg: '昵称格式不正确' });
            return;
        }
        saveNicknames();
        res.json({ code: 0, msg: '昵称更新成功' });
    });

    app.get('/api/nicknames', (req, res) => {
        res.json({
            code: 0,
            data: nicknameMap
        });
    });
    
    app.get('/api/skill-stats/:uid', (req, res) => {
        const uid = Number(req.params.uid);
        const user = userDataManager.getUser(uid);
        if (!user) return res.json({ code: 1, msg: 'User not found', data: [] });
        const totalDamage = user.damageStats?.stats?.total || 0;
        const arr = [];
        if (user.skillUsage && typeof user.skillUsage.forEach === 'function') {
            user.skillUsage.forEach((stat, skillId) => {
                const total = stat?.stats?.total || 0;
                const count = stat?.count?.total || 0;
                arr.push({
                    skill_id: Number(skillId),
                    skill_name: getSkillDisplayName(Number(skillId), total, false, false, 0),
                    total_damage: total,
                    count,
                    percentage: totalDamage > 0 ? ((total / totalDamage) * 100).toFixed(2) : 0
                });
            });
        }
        arr.sort((a, b) => b.total_damage - a.total_damage);
        res.json({ code: 0, data: arr });
    });
    app.listen(8989, () => {
        logger.info('Web Server started at http://localhost:8989');
    });

    logger.info('Welcome!');
    logger.info('Attempting to find the game server, please wait!');

    let user_uid;
    let current_server = '';
    let _data = Buffer.alloc(0);
    let tcp_next_seq = -1;
    let tcp_cache = {};
    let tcp_cache_size = 0;
    let tcp_last_time = 0;
    const tcp_lock = new Lock();

    const processPacket = (buf) => {
        try {
            // 优先使用源码解析器，内部已正确区分伤害/治疗/承伤
            try {
                packetProcessor.processPacket(buf);
                return; // 已处理，无需再走旧逻辑
            } catch (ppErr) {
                logger.debug('PacketProcessor fallback:', ppErr.message);
            }
            if (buf.length < 32) return;
            if (buf[4] & 0x80) {//zstd
                if (!zlib.zstdDecompressSync) logger.warn('zstdDecompressSync is not available! Please check your Node.js version!');
                const decompressed = zlib.zstdDecompressSync(buf.subarray(10));
                buf = Buffer.concat([buf.subarray(0, 10), decompressed]);
            }
            const data = buf.subarray(10);
            if (data.length) {
                const stream = Readable.from(data, { objectMode: false });
                let data1;
                do {
                    const len_buf = stream.read(4);
                    if (!len_buf) break;
                    data1 = stream.read(len_buf.readUInt32BE() - 4);
                    try {
                        let body = pb.decode(data1.subarray(18)) || {};
                        if (data1[17] === 0x2e) {
                            body = body[1];
                            if (body[5]) { //玩家uid
                                const uid = BigInt(body[5]) >> 16n;
                                if (user_uid !== uid) {
                                    user_uid = uid;
                                    logger.info('Got player UID! UID: ' + user_uid);
                                }
                            }
                        }
                        
                        // 深度分析用户信息（昵称、职业等）
                        try {
                            // 记录原始数据包信息
                            const packetType = data1[17];
                            logger.debug(`📦 Packet type: 0x${packetType.toString(16)}, length: ${data1.length}`);
                            
                            if (body && typeof body === 'object') {
                                // 详细记录数据包结构
                                const bodyKeys = Object.keys(body);
                                logger.debug(`🔑 Body keys: [${bodyKeys.join(', ')}], depth: ${JSON.stringify(body).length}`);
                                

                                
                                // 全方位深度数据包分析
                                const deepAnalyzePacket = (obj, path = '', depth = 0, maxDepth = 8) => {
                                    if (!obj || depth > maxDepth) return;
                                    
                                    // 记录详细路径信息
                                    if (depth <= 2) {
                                        logger.debug(`🔍 Analyzing path: ${path || 'root'}, type: ${typeof obj}, keys: ${Object.keys(obj || {}).length}`);
                                    }
                                    
                                    if (Array.isArray(obj)) {
                                        obj.forEach((item, index) => {
                                            if (item && typeof item === 'object') {
                                                const currentPath = `${path}[${index}]`;
                                                
                                                // 深度分析每个数组元素
                                                let detectedUid = null;
                                                let detectedName = null;
                                                let detectedClass = null;
                                                let allFields = {};
                                                
                                                // 收集所有字段信息
                                                for (const [key, value] of Object.entries(item)) {
                                                    allFields[key] = {
                                                        type: typeof value,
                                                        value: value,
                                                        length: typeof value === 'string' ? value.length : null
                                                    };
                                                    
                                                    // 更广泛的UID检测
                                                    if (typeof value === 'bigint' || (typeof value === 'number' && value > 100000)) {
                                                        const possibleUid = typeof value === 'bigint' ? value >> 16n : BigInt(value) >> 16n;
                                                        if (possibleUid > 0 && possibleUid < 999999999n) {
                                                            detectedUid = possibleUid;
                                                            logger.debug(`🆔 Potential UID found: ${possibleUid} at ${currentPath}.${key}`);
                                                        }
                                                    }
                                                    
                                                    // 更全面的昵称检测
                                                    if (typeof value === 'string' && value.length >= 1 && value.length <= 30) {
                                                        // 检测中文、英文、数字组合
                                                        if (/[\u4e00-\u9fa5a-zA-Z0-9_\-\.]/.test(value) && 
                                                            !/^[\d\.]+$/.test(value) && // 排除纯数字
                                                            !/^[0-9a-f]{8,}$/i.test(value) && // 排除hash值
                                                            value.length > 1) {
                                                            detectedName = value;
                                                            logger.debug(`📝 Potential name found: "${value}" at ${currentPath}.${key}`);
                                                        }
                                                    }
                                                    
                                                    // 更全面的职业检测
                                                    if (typeof value === 'number' && value >= 0 && value <= 100) {
                                                        // 检测可能的职业字段
                                                        const keyStr = key.toString().toLowerCase();
                                                        if (keyStr.includes('class') || 
                                                            keyStr.includes('job') || 
                                                            keyStr.includes('profession') ||
                                                            keyStr.includes('career') ||
                                                            keyStr.includes('role') ||
                                                            key.toString().length <= 3) { // 短字段名可能是职业ID
                                                            detectedClass = value;
                                                            logger.debug(`🎭 Potential class found: ${value} at ${currentPath}.${key}`);
                                                        }
                                                    }
                                                }
                                                
                                                // 如果找到了有用信息，尝试关联
                                                if (detectedUid || detectedName || detectedClass) {
                                                    logger.info(`🔍 Found user data at ${currentPath}:`);
                                                    logger.info(`   UID: ${detectedUid || 'none'}`);
                                                    logger.info(`   Name: ${detectedName || 'none'}`);
                                                    logger.info(`   Class: ${detectedClass || 'none'}`);
                                                    logger.info(`   All fields: ${JSON.stringify(allFields, null, 2)}`);
                                                    
                                                    // 如果有UID，保存用户信息
                                                    if (detectedUid && user_info[detectedUid]) {
                                                        if (detectedName) {
                                                            user_info[detectedUid].nickname = detectedName;
                                                            logger.info(`🎯 Updated nickname for UID ${detectedUid}: ${detectedName}`);
                                                        }
                                                        if (detectedClass !== null) {
                                                            if (professionMap[detectedClass]) {
                                                                user_info[detectedUid].profession = professionMap[detectedClass];
                                                                logger.info(`⚔️ Updated profession for UID ${detectedUid}: ${professionMap[detectedClass]} (ID: ${detectedClass})`);
                                                            } else {
                                                                logger.info(`❓ Unknown profession ID ${detectedClass} for UID ${detectedUid}`);
                                                            }
                                                        }
                                                    }
                                                    
                                                    // 即使没有UID，也记录可能的用户信息
                                                    if (!detectedUid && (detectedName || detectedClass)) {
                                                        logger.info(`📋 Orphaned user data (no UID): name="${detectedName}", class=${detectedClass}`);
                                                    }
                                                }
                                                
                                                // 继续递归分析
                                                deepAnalyzePacket(item, currentPath, depth + 1, maxDepth);
                                            }
                                        });
                                    } else if (obj && typeof obj === 'object') {
                                        // 分析对象的所有属性
                                        for (const [key, value] of Object.entries(obj)) {
                                            const currentPath = path ? `${path}.${key}` : key;
                                            if (value && typeof value === 'object') {
                                                deepAnalyzePacket(value, currentPath, depth + 1, maxDepth);
                                            }
                                        }
                                    }
                                };
                                
                                // 开始深度分析
                                deepAnalyzePacket(body);
                                
                                // 额外分析：查找字符串模式
                                const findStringPatterns = (obj, path = '') => {
                                    if (!obj || typeof obj !== 'object') return;
                                    
                                    if (Array.isArray(obj)) {
                                        obj.forEach((item, index) => {
                                            findStringPatterns(item, `${path}[${index}]`);
                                        });
                                    } else {
                                        for (const [key, value] of Object.entries(obj)) {
                                            if (typeof value === 'string' && value.length > 0) {
                                                logger.debug(`🔤 String at ${path}.${key}: "${value}" (length: ${value.length})`);
                                            } else if (typeof value === 'object' && value !== null) {
                                                findStringPatterns(value, path ? `${path}.${key}` : key);
                                            }
                                        }
                                    }
                                };
                                
                                if (logger.level === 'debug') {
                                    findStringPatterns(body);
                                }
                            }
                        } catch (e) {
                            logger.error('深度分析用户信息时出错:', e.message);
                            logger.debug('Error stack:', e.stack);
                            logger.debug('Error occurred in packet type: 0x' + (typeof packetType !== 'undefined' ? packetType.toString(16) : 'unknown'));
                            if (body) {
                                try {
                                    logger.debug('Body structure:', JSON.stringify(body, null, 2).substring(0, 500) + '...');
                                } catch (jsonError) {
                                    logger.debug('Body structure could not be serialized:', jsonError.message);
                                }
                            }
                        }
                        let body1 = body[1];
                        if (body1) {
                            if (!Array.isArray(body1)) body1 = [body1];
                            for (const b of body1) {
                                if (b[7] && b[7][2]) {
                                    logger.debug(b.toBase64());
                                    
                                    // 获取目标UUID（受击者）- 这是关键修复！
                                    const target_uuid = BigInt(b[5] || 0); // b[5]是目标UUID
                                    const is_target_player = (target_uuid & 0xffffn) === 640n;
                                    const target_uid = target_uuid >> 16n;
                                    
                                    const hits = Array.isArray(b[7][2]) ? b[7][2] : [b[7][2]];
                                    for (const hit of hits) {
                                        const skill = hit[12];
                                        if (typeof skill !== 'number') break;
                                        const value = hit[6], luckyValue = hit[8], isMiss = hit[2], isCrit = hit[5], hpLessenValue = hit[9] ?? 0;
                                        const damage = value ?? luckyValue;
                                        
                                        // 获取攻击者UUID
                                        const attacker_uuid = BigInt(hit[21] || hit[11]);
                                        const is_attacker_player = (attacker_uuid & 0xffffn) === 640n;
                                        const attacker_uid = attacker_uuid >> 16n;
                                        
                                        if (!is_attacker_player && !is_target_player) break; // 排除非玩家相关攻击
                                        if (typeof damage !== 'number') break;

                                        // 检测是否为治疗
                                        const isHeal = hit[3] === 2 || hit[0] === 2 || false;
                                        
                                        if (is_target_player) {
                                            // 玩家目标
                                            if (isHeal) {
                                                // 玩家被治疗
                                                if (is_attacker_player) {
                                                    // 只记录玩家造成的治疗
                                                    userDataManager.addHealing(Number(attacker_uid), damage, !!isCrit, !!luckyValue);
                                                    logger.info(`💚 Healing: Attacker ${attacker_uid} healed Target ${target_uid} for ${damage}`);
                                                }
                                            } else {
                                                // 玩家受到伤害 - 这是承伤的关键！
                                                userDataManager.addTakenDamage(Number(target_uid), damage);
                                                logger.info(`🛡️ TakenDamage: Target ${target_uid} took ${damage} damage from ${is_attacker_player ? `Player ${attacker_uid}` : 'Non-Player'} Skill: ${skill}`);
                                            }
                                        } else {
                                            // 非玩家目标
                                            if (isHeal) {
                                                // 治疗非玩家目标，忽略
                                            } else {
                                                // 玩家对非玩家造成伤害
                                                if (is_attacker_player) {
                                                    userDataManager.addDamage(Number(attacker_uid), skill, damage, !!isCrit, !!luckyValue, hpLessenValue);
                                                    logger.info(`⚔️ Damage: Attacker ${attacker_uid} dealt ${damage} damage to Non-Player with Skill: ${skill}`);
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    //logger.debug(data1.toString('hex'));
                                }
                            }
                        } else {
                            //logger.debug(data1.toString('hex'));
                        }
                    } catch (e) {
                        logger.debug(e);
                        logger.debug(data1.subarray(18).toString('hex'));
                    }
                } while (data1 && data1.length)
            }
        } catch (e) {
            logger.debug(e);
        }
    }
    const clearTcpCache = () => {
        _data = Buffer.alloc(0);
        tcp_next_seq = -1;
        tcp_last_time = 0;
        tcp_cache = {};
        tcp_cache_size = 0;
    }

    //抓包相关
    const c = new Cap();
    const device = devices[num].name;
    const filter = 'ip and tcp';
    const bufSize = 10 * 1024 * 1024;
    const buffer = Buffer.alloc(65535);
    const linkType = c.open(device, filter, bufSize, buffer);
    c.setMinBytes && c.setMinBytes(0);
    c.on('packet', async function (nbytes, trunc) {
        const buffer1 = Buffer.from(buffer);
        if (linkType === 'ETHERNET') {
            var ret = decoders.Ethernet(buffer1);
            if (ret.info.type === PROTOCOL.ETHERNET.IPV4) {
                ret = decoders.IPV4(buffer1, ret.offset);
                //logger.debug('from: ' + ret.info.srcaddr + ' to ' + ret.info.dstaddr);
                const srcaddr = ret.info.srcaddr;
                const dstaddr = ret.info.dstaddr;

                if (ret.info.protocol === PROTOCOL.IP.TCP) {
                    var datalen = ret.info.totallen - ret.hdrlen;

                    ret = decoders.TCP(buffer1, ret.offset);
                    //logger.debug(' from port: ' + ret.info.srcport + ' to port: ' + ret.info.dstport);
                    const srcport = ret.info.srcport;
                    const dstport = ret.info.dstport;
                    const src_server = srcaddr + ':' + srcport + ' -> ' + dstaddr + ':' + dstport;
                    datalen -= ret.hdrlen;
                    let buf = Buffer.from(buffer1.subarray(ret.offset, ret.offset + datalen));

                    if (tcp_last_time && Date.now() - tcp_last_time > 30000) {
                        logger.warn('Cannot capture the next packet! Is the game closed or disconnected? seq: ' + tcp_next_seq);
                        current_server = '';
                        clearTcpCache();
                    }

                    if (current_server !== src_server) {
                        try {
                            //尝试通过小包识别服务器
                            if (buf[4] == 0) {
                                const data = buf.subarray(10);
                                if (data.length) {
                                    const stream = Readable.from(data, { objectMode: false });
                                    let data1;
                                    do {
                                        const len_buf = stream.read(4);
                                        if (!len_buf) break;
                                        data1 = stream.read(len_buf.readUInt32BE() - 4);
                                        const signature = Buffer.from([0x00, 0x63, 0x33, 0x53, 0x42, 0x00]); //c3SB??
                                        if (Buffer.compare(data1.subarray(5, 5 + signature.length), signature)) break;
                                        try {
                                            let body = pb.decode(data1.subarray(18)) || {};
                                            if (current_server !== src_server) {
                                                current_server = src_server;
                                                clearTcpCache();
                                                logger.info('Got Scene Server Address: ' + src_server);
                                            }
                                            if (data1[17] === 0x2e) {
                                                body = body[1];
                                                if (body[5]) { //玩家uid
                                                    if (!user_uid) {
                                                        user_uid = BigInt(body[5]) >> 16n;
                                                        logger.info('Got player UID! UID: ' + user_uid);
                                                    }
                                                }
                                            }
                                        } catch (e) { }
                                    } while (data1 && data1.length)
                                }
                            }
                        } catch (e) { }
                        return;
                    }
                    //这里已经是识别到的服务器的包了
                    await tcp_lock.acquire();
                    if (tcp_next_seq === -1 && buf.length > 4 && buf.readUInt32BE() < 999999) { //第一次抓包可能抓到后半段的，先丢了
                        tcp_next_seq = ret.info.seqno;
                    }
                    logger.debug('TCP next seq: ' + tcp_next_seq);
                    tcp_cache[ret.info.seqno] = buf;
                    tcp_cache_size++;
                    while (tcp_cache[tcp_next_seq]) {
                        const seq = tcp_next_seq;
                        _data = _data.length === 0 ? tcp_cache[seq] : Buffer.concat([_data, tcp_cache[seq]]);
                        tcp_next_seq = (seq + tcp_cache[seq].length) >>> 0; //uint32
                        tcp_cache[seq] = undefined;
                        tcp_cache_size--;
                        tcp_last_time = Date.now();
                        setTimeout(() => {
                            if (tcp_cache[seq]) {
                                tcp_cache[seq] = undefined;
                                tcp_cache_size--;
                            }
                        }, 10000);
                    }
                    /*
                    if (tcp_cache_size > 30) {
                        logger.warn('Too much unused tcp cache! Is the game reconnected? seq: ' + tcp_next_seq + ' size:' + tcp_cache_size);
                        clearTcpCache();
                    }
                    */
                    while (_data.length > 4) {
                        let len = _data.readUInt32BE();
                        if (_data.length >= len) {
                            const packet = _data.subarray(0, len);
                            _data = _data.subarray(len);
                            processPacket(packet);
                                            } else {
                            if (len > 999999) {
                                logger.error(`Invalid Length!! ${_data.length},${len},${_data.toString('hex')},${tcp_next_seq}`);
                                process.exit(1)
                            }
                            break;
                        }
                    }
                    tcp_lock.release();
                } else
                    logger.error('Unsupported IPv4 protocol: ' + PROTOCOL.IP[ret.info.protocol]);
            } else
                logger.error('Unsupported Ethertype: ' + PROTOCOL.ETHERNET[ret.info.type]);
        }
    })
}

main();
